#include "fichier.h"
#define TAILLE_ARBO_MAX 2048
#define TAILLE_FICH_MAX 64
#define TAILLE_DOSS_MAX TAILLE_ARBO_MAX-TAILLE_FICH_MAX

#define STR_VALUE(val) #val
#define STR(name) STR_VALUE(name)


#define PATH_LEN 256
#define MD5_LEN 32

/**
 *
 */
int fichier_liste ( const char * dossier , int niveau){
    DIR * dir;
    char doss[TAILLE_DOSS_MAX +1];
    char arbo[TAILLE_ARBO_MAX +1];
    char md5[MD5_LEN + 1];
    int fversion = 1;

    sqlite3 *bd;
    int rc;

    struct dirent * contenus;

    /* le nom de dossier est il trop grand? */
    if( TAILLE_DOSS_MAX < strlen(dossier) )
    {
        return 47;
    }

    strcpy(doss, dossier);


    /* ouverture du dossier */
    if ( NULL == (dir = opendir(doss))){
        perror( "erreur d'ouverture du dossier %s !");
        return 1 ;
    }

    /* il y a t'il '/' a la fin? */
    if ( doss[strlen(doss)-1] != '/' )
    {
        if ( TAILLE_DOSS_MAX  < strlen(doss) )
            return 47;
        doss[strlen(doss)+1] = '\0';
        doss[strlen(doss)] = '/';
    }
    printf("%s\n", doss);

    //test de connexion à la base de donnée    
    rc = sqlite3_open ("bdd.db", &bd);

    if (rc){
        fprintf (stderr, "impossible d'ouvrir la base: %s\n", sqlite3_errmsg (bd));
        sqlite3_close (bd);
        exit (1);
    }
    //test de creation de la table
    if (niveau == 0) {

        if(0 != sql_requete("CREATE TABLE table1 (arbo varchar(150), ftype char, fdate varchar(60), fversion int, fmd5 varchar(60), PRIMARY KEY (arbo, ftype));", bd)){
            printf("echec de la creation de table\n");
        }

        //Table qui stockera les noms et type de fichier
        if(0 != sql_requete("CREATE TABLE table2 (arbo varchar(150), ftype char, PRIMARY KEY (arbo, ftype));", bd)){
            printf("Echec de la creation de table2\n");    
        }

         sql_requete("DELETE FROM table2;", bd);
    }

    //parcours des dossiers
    while( (contenus = readdir(dir))){
        if ( ( strncmp(contenus->d_name, ".", 1) != 0 ) && ( strncmp(contenus->d_name, "..", 2 ) != 0 ) ){

            //Copie chemin arborescence dans la variable doss
            strcpy(arbo, doss);

            //Verification de la taille
            if ( TAILLE_ARBO_MAX == strlen(arbo) )
                return 2001;


            strcat(arbo,(char *) (contenus->d_name));
            espace(niveau);

            char requete[1024];
            //int rc;
            char *zErrMsg;

	    sprintf(requete,"INSERT INTO table2 (arbo, ftype) values ('%s', '%c');",arbo, fichier_type(arbo ));
            if (sql_requete(requete, bd) != 0)
		printf("echec insert table 2 \n");

            fichier_MD5(arbo, md5);
            // VERIFICATION DU FICHIER
            sprintf(requete,"INSERT INTO table1 (arbo, ftype, fdate, fversion, fmd5) values ('%s', '%c', '%s', '%d', '%s');",arbo, fichier_type(arbo ), fichier_LastMod(arbo), fversion, md5);
            printf("requete : %s",requete);
             
            if (sql_requete(requete, bd) == 0){
       
                printf("valeur requete : %d\n",sql_requete(requete,bd));        
                //Le fichier n'existe pas, on le créé
                printf("Fichier ajouté\n");
            } else {

               
                printf("valeur requete : %d\n",sql_requete(requete,bd));        
                //Le fichier existe, on va d'abord verifier si le fichier recu a ete modifie.
                char ** resultat;
                int nrow,ncolumn;
                sprintf(requete,"SELECT fmd5 FROM table1 WHERE arbo = '%s';", arbo);
                sqlite3_get_table(bd,requete,&resultat,&nrow,&ncolumn,&zErrMsg);
                printf("resultat requete select : %s\t", resultat[1]);
                printf("\n");
                if ((strcmp(resultat[1], md5)) == 0){
                        printf("Pas de changement !\n");
                } else {
                        printf("changement repere !\n");
                // Appel fonction pour incrémenter la version
                fversion = verif_version(arbo);
                //Requête mettant à jour le fichier avec la nouvelle version
                sprintf(requete,"UPDATE table1 SET fdate = '%s', fversion = '%d', fmd5 = '%s' WHERE arbo = '%s' AND ftype = '%c';", fichier_LastMod(arbo), fversion, md5, arbo, fichier_type(arbo));
                printf("requete update : %s\n", requete);
                sql_requete(requete, bd);
                printf("Ma nouvelle version est %d\n", fversion);

                printf("!!!! envoi du fichier %s au serveur !!!!\n", arbo);
                }    
            }

            /* printf("%c %s %s %s\n", fichier_type(arbo ) , arbo , fichier_LastMod(arbo), md5 );
            */

            if('d' == fichier_type(arbo)){
                fichier_liste(arbo , niveau +1);
            }


        }
    }
    //fermeture de la connexion à la base
    sqlite3_close (bd);

    closedir(dir);
    free(contenus );
    return 0;
}


/**
 *Fonction qui retourne le type du fichier : f pour file,
 *t pour , t pour tube, c pour ??, b pour ??,
 * d pour dossier, l pour ?? et e s'il y a une erreur      
 */
char fichier_type( const char * fichier){
    struct stat infos;

    if ( -1 == stat(fichier, &infos)){
        perror("erreur d'ouverture des caracteristiques du fichier");
        return 'e';
    }
    if ( S_ISREG( infos.st_mode) )
        return 'f';

    if ( S_ISFIFO( infos.st_mode ) )
        return 't';

    if ( S_ISCHR( infos.st_mode ) )
        return 'c';

    if ( S_ISBLK( infos.st_mode ) )
        return 'b';

    if ( S_ISDIR( infos.st_mode ) )
        return 'd';

    if ( S_ISLNK ( infos.st_mode ) )
        return 'l';

    /*if ( S_ISSOCK ( infos.st_mode ) )
      return 's';*/

    return 'e';
}

//Fonction qui retourne la date d'un fichier
time_t fichier_date( const char * fichier){
    struct stat infos;

    if ( -1 == stat(fichier, &infos)){
        perror("erreur d'ouverture des caracteristiques du fichier");
        return 0;
    }

    return infos.st_mtime;
}

//Fonction
void espace(int nb){
    int i;
    if (nb< 0)
        printf(" ");
    else
        for(i=0; i< nb; ++i)
            printf(" ");
}

char* fichier_LastMod(char *path) {
    struct stat attr;
    stat(path, &attr);

    return ctime(&attr.st_mtime);
}


int fichier_MD5(char *file_name, char *md5_sum)
{
#define MD5SUM_CMD_FMT "md5sum %." STR(PATH_LEN) "s 2>/dev/null"
    char cmd[PATH_LEN + sizeof (MD5SUM_CMD_FMT)];
    sprintf(cmd, MD5SUM_CMD_FMT, file_name);
#undef MD5SUM_CMD_FMT

    FILE *p = popen(cmd, "r");
    if (p == NULL) return 0;

    int i, ch;
    for (i = 0; i < MD5_LEN && isxdigit(ch = fgetc(p)); i++) {
        *md5_sum++ = ch;
    }

    *md5_sum = '\0';
    pclose(p);
    return i == MD5_LEN;
}


int callback (void *lokis, int nbCol, char **data, char **nomCol){
    for (int i = 0; i < nbCol; i++){
        printf ("%s \t", data[i]);
    }
    printf ("\n");
    return 0;
}

int sql_requete(char * requete, sqlite3 *db) {
    char *zErrMsg = 0;
    if (sqlite3_exec (db, requete, callback, 0, &zErrMsg) != SQLITE_OK){
        return 1;
    }
    return 0;
}

int verif_version(char arbo[1024]){

    sqlite3 *bd;
    int rc, nrow, ncolumn;
    int version;
    char ** resultat;
    char requete[1024];
    char *zErrMsg;

    //Connexion à la base + vérification
    rc = sqlite3_open ("bdd.db", &bd);
    if (rc){
        fprintf (stderr, "impossible d'ouvrir la base : %s\n", sqlite3_errmsg (bd));
        sqlite3_close(bd);
        exit (1);
    }

    //Requete pour sélectionner la version du fichier
    sprintf(requete,"SELECT fversion FROM table1 WHERE arbo = '%s';", arbo);
    printf("requete version : %s\n", requete);
    sqlite3_get_table(bd,requete,&resultat,&nrow,&ncolumn,&zErrMsg);
    version = atoi(resultat[1]);
    //fermeture de la connexion à la base
    sqlite3_close (bd);

        return version+1;
}

int delete_fichier(void){

    sqlite3 *bd;
    int rc, nrow, ncolumn;
    char ** resultat;
    char requete[1024];
    char *zErrMsg;


    //test de connexion à la base de donnée    
    rc = sqlite3_open ("bdd.db", &bd);

    if (rc){
        fprintf (stderr, "impossible d'ouvrir la base: %s\n", sqlite3_errmsg (bd));
        sqlite3_close (bd);
        return 1;
    }

    sprintf(requete,"SELECT arbo from table1 WHERE arbo NOT IN (SELECT arbo from table2);");
    printf("requete supression : %s\n", requete);
    sqlite3_get_table(bd,requete,&resultat,&nrow,&ncolumn,&zErrMsg);
    printf("%d\n", nrow);
    if(nrow > 0){
        for (int i = 1; i <= (nrow)* (ncolumn); i++){
            printf("%d %s\n",i, resultat[i]);
            sprintf(requete,"DELETE FROM table1 WHERE arbo = '%s'", resultat[i]);
            if (sql_requete(requete, bd) == 0){
                 printf("fichier correctement supprimer\n");
		/*
		*Code supression !!!
		*/
       	    }else{
	    	    printf("echec de la suppression\n");
	    }
        }

        printf("Les fichier ont bien etai suprimé\n");
    } else {
        printf("pas de supression a effectuer\n");
    }
    //fermeture de la connexion à la base
    sqlite3_close (bd);
    return 0;
}

